package com.ruoyi.tzai.service.tts.impl;

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.tzai.service.tts.ITTSService;
import com.ruoyi.tzai.service.IFileUploadService;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.dromara.x.file.storage.core.FileInfo;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Azure Neural TTS服务实现
 * 支持词级时间戳
 * 
 * @author tzai
 * @date 2025-10-27
 */
@Service("azureTTSService")
public class AzureTTSServiceImpl implements ITTSService 
{
    private static final Logger log = LoggerFactory.getLogger(AzureTTSServiceImpl.class);
    
    @Value("${ruoyi.profile:/tmp}")
    private String uploadPath;
    
    @Autowired
    private IFileUploadService fileUploadService;
    
    private String subscriptionKey;
    private String region = "eastus";
    private String apiEndpoint;
    
    /**
     * 手动设置文件上传服务（用于工厂创建时注入依赖）
     */
    public void setFileUploadService(IFileUploadService fileUploadService) {
        this.fileUploadService = fileUploadService;
    }
    
    private final OkHttpClient httpClient = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(120, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();

    @Override
    public TTSResult generateSpeech(String text, String language, String voiceName) {
        log.info("生成语音 - 语言: {}, 文本长度: {}, 音色: {}", language, text.length(), voiceName);
        
        // 如果未指定音色，使用默认音色
        if (voiceName == null || voiceName.isEmpty()) {
            voiceName = language.equals("en") ? "en-US-JennyNeural" : "zh-CN-XiaoxiaoNeural";
        }
        
        // 检查配置
        if (subscriptionKey == null || subscriptionKey.isEmpty()) {
            log.error("未配置Subscription Key，无法调用Azure TTS");
            throw new RuntimeException("Azure TTS配置缺失：需要配置Subscription Key");
        }

        try {
            // 构建SSML
            String ssml = buildSSML(text, voiceName);
            
            // 调用Azure TTS API
            String endpoint = String.format("https://%s.tts.speech.microsoft.com/cognitiveservices/v1", region);
            if (apiEndpoint != null && !apiEndpoint.isEmpty()) {
                endpoint = apiEndpoint;
            }

            Request request = new Request.Builder()
                    .url(endpoint)
                    .addHeader("Ocp-Apim-Subscription-Key", subscriptionKey)
                    .addHeader("Content-Type", "application/ssml+xml")
                    .addHeader("X-Microsoft-OutputFormat", "audio-24khz-48kbitrate-mono-mp3")
                    .addHeader("User-Agent", "TZAI-TTS-Service")
                    .post(RequestBody.create(ssml, MediaType.parse("application/ssml+xml")))
                    .build();

            try (Response response = httpClient.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    String errorBody = response.body() != null ? response.body().string() : "";
                    log.error("Azure TTS API调用失败: HTTP {}, {}", response.code(), errorBody);
                    throw new IOException("Azure TTS API调用失败: HTTP " + response.code());
                }

                // 获取音频数据
                byte[] audioData = response.body().bytes();
                log.info("Azure TTS API调用成功，音频大小: {} bytes", audioData.length);
                
                // 上传到OSS
                String fileName = UUID.randomUUID().toString() + ".mp3";
                FileInfo fileInfo = fileUploadService.uploadAudio(
                    new ByteArrayInputStream(audioData), 
                    fileName, 
                    audioData.length
                );

                // 获取词级时间戳
                String timestamps = getWordTimestamps(text, voiceName);

                // 构建结果
                TTSResult result = new TTSResult();
                if (fileInfo != null) {
                    result.setAudioUrl(fileInfo.getUrl());
                    result.setFileMetadata(JSON.toJSONString(fileInfo));
                }
                result.setFileSize((long) audioData.length);
                result.setTimestamps(timestamps);
                result.setDuration(estimateDuration(text));

                return result;
            }
        } catch (IOException e) {
            log.error("Azure TTS生成失败: {}", e.getMessage(), e);
            throw new RuntimeException("Azure TTS生成失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取词级时间戳
     * TODO: 调用Azure TTS Word Boundary API获取精确时间戳
     */
    private String getWordTimestamps(String text, String voiceName) {
        try {
            // TODO: 调用Azure TTS Word Boundary API获取精确时间戳
            // 这里需要使用WebSocket连接或批量API
            
            // 临时实现：基于文本估算时间戳
            JSONArray timestamps = new JSONArray();
            String[] words = text.split("\\s+|(?<=[\\u4e00-\\u9fa5])");
            double currentTime = 0.0;
            
            for (String word : words) {
                if (word.trim().isEmpty()) continue;
                
                JSONObject timestamp = new JSONObject();
                timestamp.put("word", word);
                timestamp.put("start", currentTime);
                
                // 估算每个词的时长（可以根据实际情况调整）
                double wordDuration = word.length() * 0.15; // 平均每个字0.15秒
                currentTime += wordDuration;
                
                timestamp.put("end", currentTime);
                timestamps.add(timestamp);
            }
            
            return timestamps.toJSONString();
        } catch (Exception e) {
            log.error("获取词级时间戳失败", e);
            return "[]";
        }
    }

    /**
     * 构建SSML
     */
    private String buildSSML(String text, String voiceName) {
        return String.format(
            "<speak version='1.0' xml:lang='zh-CN' xmlns='http://www.w3.org/2001/10/synthesis'>" +
            "<voice name='%s'>%s</voice>" +
            "</speak>",
            voiceName, text
        );
    }

    /**
     * 估算音频时长
     */
    private double estimateDuration(String text) {
        // 粗略估算：中文每字0.3秒，英文每词0.4秒
        int chineseChars = text.replaceAll("[^\\u4e00-\\u9fa5]", "").length();
        int englishWords = text.split("\\s+").length;
        return chineseChars * 0.3 + englishWords * 0.4;
    }

    @Override
    public boolean testConnection() {
        try {
            TTSResult result = generateSpeech("Hello", "en", null);
            return result != null && result.getAudioUrl() != null;
        } catch (Exception e) {
            log.error("Azure TTS连接测试失败", e);
            return false;
        }
    }

    @Override
    public String getEngineName() {
        return "Azure Neural TTS";
    }

    @Override
    public boolean supportsWordTimestamp() {
        return true;
    }

    // Setters for configuration
    public void setSubscriptionKey(String subscriptionKey) {
        this.subscriptionKey = subscriptionKey;
    }

    public void setRegion(String region) {
        this.region = region;
    }

    public void setApiEndpoint(String apiEndpoint) {
        this.apiEndpoint = apiEndpoint;
    }
}

